package org.apache.rocketmq.client.java.message;

import com.google.common.base.MoreObjects;
import org.apache.rocketmq.client.java.clientapis.message.Message;

import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.*;

/**
 * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
 * @author：陈清风扬，个人微信号：chenqingfengyangjj。
 * @date:2025/6/16
 * @方法描述：消息实现类
 */
public class MessageImpl implements Message {
    //消息的key集合，看到这个成员变量，大家应该能意识到，每一条消息其实可以有多个key
    protected final Collection<String> keys;

    //消息体，也就是消息的实际内容
    final byte[] body;

    //消息所属的主题
    private final String topic;

    //消息的标签，可以在主题之下对消息继续进行细分
    @Nullable
    private final String tag;

    //消息分组，在发送顺序消息时会用到这个成员变量
    @Nullable
    private final String messageGroup;

    //消息延迟投递的时间，可以在指定时间后投递消息
    @Nullable
    private final Long deliveryTimestamp;

    //父级跟踪上下文，在源码中并没有为这个成员变量赋值
    //大家可以在自己的项目中自行设置
    @Nullable
    private final String parentTraceContext;

    //该成员变量存储的就是消息的额外内容，可以由用户自己定义
    private final Map<String, String> properties;

    //构造方法
    MessageImpl(String topic, byte[] body, @Nullable String tag, Collection<String> keys,
                @Nullable String messageGroup, @Nullable String parentTraceContext, @Nullable Long deliveryTimestamp,
                Map<String, String> properties) {
        this.topic = topic;
        this.body = body;
        this.tag = tag;
        this.messageGroup = messageGroup;
        this.deliveryTimestamp = deliveryTimestamp;
        this.keys = keys;
        this.parentTraceContext = parentTraceContext;
        this.properties = properties;
    }


    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：使用已有的消息对象创建新的消息对象的构造方法
     */
    MessageImpl(Message message) {

        this.topic = message.getTopic();
        if (message instanceof MessageImpl) {
            MessageImpl impl = (MessageImpl) message;
            this.body = impl.body;
        } else {
            final ByteBuffer body = message.getBody();
            byte[] bytes = new byte[body.remaining()];
            body.get(bytes);
            this.body = bytes;
        }
        this.tag = message.getTag().orElse(null);
        this.messageGroup = message.getMessageGroup().orElse(null);
        this.deliveryTimestamp = message.getDeliveryTimestamp().orElse(null);
        this.parentTraceContext = message.getParentTraceContext().orElse(null);
        this.keys = message.getKeys();
        this.properties = message.getProperties();
    }

    /**
     * @课程描述:从零带你写框架系列中的课程，整个系列包含netty，xxl-job，rocketmq，nacos，sofajraft，spring，springboot，disruptor，编译器，虚拟机等等。
     * @author：陈清风扬，个人微信号：chenqingfengyangjj。
     * @方法描述：得到消息通用信息的方法
     */
    public MessageCommon getMessageCommon() {
        return new MessageCommon(topic, body, tag, messageGroup, deliveryTimestamp, parentTraceContext, keys, properties);
    }


    @Override
    public String getTopic() {
        return topic;
    }


    @Override
    public ByteBuffer getBody() {
        return ByteBuffer.wrap(body).asReadOnlyBuffer();
    }


    @Override
    public Map<String, String> getProperties() {
        return new HashMap<>(properties);
    }


    @Override
    public Optional<String> getTag() {
        return null == tag ? Optional.empty() : Optional.of(tag);
    }


    @Override
    public Collection<String> getKeys() {
        return new ArrayList<>(keys);
    }

    @Override
    public Optional<Long> getDeliveryTimestamp() {
        return null == deliveryTimestamp ? Optional.empty() : Optional.of(deliveryTimestamp);
    }


    @Override
    public Optional<String> getMessageGroup() {
        return null == messageGroup ? Optional.empty() : Optional.of(messageGroup);
    }


    @Override
    public Optional<String> getParentTraceContext() {
        return null == parentTraceContext ? Optional.empty() : Optional.of(parentTraceContext);
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("topic", topic)
                .add("tag", tag)
                .add("messageGroup", messageGroup)
                .add("deliveryTimestamp", deliveryTimestamp)
                .add("parentTraceContext", parentTraceContext)
                .add("keys", keys)
                .add("properties", properties)
                .toString();
    }
}
